package Server;

import java.net.*;
import java.io.*;
import java.lang.*;

//declaration of class gameserver
class GameServer {

	static int users = 0; // the number of active users
	static int unique_id = 1; // setup unique id number for users
	static int DEFAULT_PORT = 8999;
	static networksocket clients[] = new networksocket[29];

	public static void main(String args[]) {

		ServerSocket serverSocket = null;
		int i, port = 0, connectTest;
		boolean chatFlag = true;

		if (args.length == 1) {
			try {
				port = Integer.parseInt(args[0]);
			} catch (NumberFormatException e) {
				port = 0;
			}
		}
		if (port == 0)
			port = DEFAULT_PORT;

		try {
			serverSocket = new ServerSocket(port);
			System.out.println("listen on port: " + String.valueOf(port));
		} catch (IOException e) {
			System.out.println("Could not listen on port: " + e);
			System.exit(1);
		}

		Socket clientSocket = null;
		Connection user = new Connection(serverSocket);

		if (users == 0) { // if no users, wait for one
			try {
				System.out.println("wait for a user");
				clientSocket = serverSocket.accept();
				System.out.println("accept a user");

			} catch (IOException e) {
				System.out.println("Accept failed: " + e);
				System.exit(1);
			}
			add_client(new networksocket(clientSocket)); // add the client
		}

		String inputStream; // string for Input IO
		String outputStream; // string for Output IO

		// get the vector the write to

		user.start(); // start polling for new users
		try {
			inputStream = "Connected! Double-click user to challenge";
			i = users;
			while (users >= 0) {
				if (users > 0 && i <= users) {
					connectTest = clients[i].is_readable();
					if (connectTest == -1) { // if connection stale
						remove_client(i); // remove the client
					} else if (connectTest == 1) { // if there is a line to get
						inputStream = clients[i].read_stream(); // get the
						// string
						chatFlag = process_line(inputStream, i); // process the
						// line
						if (chatFlag) { // echo line if is plain text
							if (clients[i] != null)
								System.out.println(clients[i].name + ": "
										+ inputStream);
							write_all((clients[i].name).toUpperCase() + ": "
									+ inputStream); // echo it
						}
					}
				}
				try {
					user.join(2); // give connection testing some time
				} catch (InterruptedException e) {
				}
				if (user.connected() == true) {
					add_client(new networksocket(user.get_socket()));
					user.resume();
				}
				i++;
				if (i > users && users >= 1)
					i = 1;
				if (i > users && users < 1)
					i = 0;
			}
			serverSocket.close();
		} catch (IOException e) {
		}
	}

	// sends all the names and IDs in the servers list to all the clients
	static void send_names() {

		String names = new String("!!names!!"); // start with indicator
		int i;

		if (users < 1)
			return; // do nothing for a no users
		for (i = 1; i <= users; i++)
			// add all users
			if (clients[i] != null) // if everthing is in order
				names = names + Integer.toString(clients[i].id) + "~"
						+ clients[i].name + "|"; // append names and delimiters
		write_all(names); // echo the names to everyone
	}

	// process the incoming data stream and return a status flag
	static boolean process_line(String line, int i) {

		int next, usernum;
		String temp;
		String directive = new String("!!directive!!"); // new indicator

		// false if don't echo line

		if (line.startsWith("!!directive!!")) { // instruction to send directive
			// to users
			line = line.substring(13);
			next = line.indexOf('|'); // get position of next delimeters
			directive = directive + line.substring(0, next) + ","
					+ clients[i].name;
			line = line.substring(next + 1);
			while (line.length() > 0) { // send directive to players in list
				next = line.indexOf('|');
				if (next == -1)
					break; // end of list
				temp = line.substring(0, next); // check for range
				if ((Integer.parseInt(temp)) > users)
					break;
				clients[Integer.parseInt(temp)].write_stream(directive);
				line = line.substring(next + 1);
			}
			return false;
		}

		else if (line.startsWith("!!name!!")) { // instruction to change name
			clients[i].name = line.substring(8); // name is the rest of line
			clients[i].write_stream("Name changed to " + line.substring(8));
			System.out.println(line.substring(8) + " enters");
			send_names(); // send an updated names list
			return false; // don't echo this string
		}

		else if (line.equals("!!quit!!")) { // instruction to quit
			write_all(clients[i].name + " is logging out."); // tell everyone
			System.out.println(clients[i].name + " logged out");
			remove_client(i);
			return false;
		}
		return true;

	}

	// writes the string to all the users contained in the server's list
	static void write_all(String text) { // write to all the clients

		int i;

		for (i = 1; i <= users; i++)
			clients[i].write_stream(text);
	}

	// adds a client and assigns it a unique id, then updates client name lists
	static void add_client(networksocket client) {
		synchronized (clients) {

			if (users >= 25) {
				client.write_stream("Sorry, there already 25 users.");
				client.kill(); // don't allow too many
				return;
			}

			clients[++users] = client; // add the client to the list
			clients[users].id = unique_id++;
			clients[users].write_stream("!!directive!!mssge,uid,"
					+ Integer.toString(clients[users].id));
			clients[users]
					.write_stream("Connected! Double-click user to challenge");
			send_names(); // update everyones names list
		}
	}

	// removes a client from the list and updates the client name lists
	static void remove_client(int client) {
		synchronized (clients) {

			clients[client].kill(); // close everything
			clients[client] = clients[users];
			clients[users] = null;
			users--;
			if (users <= 0)
				unique_id = 1;
			send_names(); // update the names list
		}
	}

}